home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / mac / raytrace / rayshade / ryshdmst.hqx / Rayshade / Source / raytrace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-14  |  12.0 KB  |  512 lines

  1. /*
  2.  * raytrace.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * $Id: raytrace.c,v 4.0 91/07/17 14:50:49 kolb Exp Locker: kolb $
  17.  *
  18.  * $Log:    raytrace.c,v $
  19.  * Revision 4.0  91/07/17  14:50:49  kolb
  20.  * Initial version.
  21.  * 
  22.  */
  23.  
  24. #include "rayshade.h"
  25. #include "atmosphere.h"
  26. #include "surface.h"
  27. #include "sampling.h"
  28. #include "options.h"
  29. #include "stats.h"
  30. #include "raytrace.h"
  31. #include "viewing.h"
  32.  
  33. #define UNSAMPLED    -1
  34. #define SUPERSAMPLED    -2
  35.  
  36. typedef struct {
  37.     Pixel *pix;        /* Pixel values */
  38.     int      *samp;    /* Sample number */
  39. } Scanline;
  40.  
  41. static int *SampleNumbers;
  42. static void    RaytraceInit();
  43.  
  44. static char halt_rendering ;
  45. static Ray    TopRay;                /* Top-level ray. */
  46. Float SampleTime();
  47.  
  48. Pixel    WhitePix = {1., 1., 1., 1.},
  49.         BlackPix = {0., 0., 0., 0.};
  50.  
  51. /*
  52.  * "Dither matrices" used to encode the 'number' of a ray that samples a
  53.  * particular portion of a pixel.  Hand-coding is ugly, but...
  54.  */
  55. static int OneSample[1] =  {0};
  56. static int TwoSamples[4] = {
  57.     0, 2,
  58.     3, 1
  59. };
  60. static int ThreeSamples[9] = {
  61.     0, 2, 7,
  62.     6, 5, 1,
  63.     3, 8, 4
  64. };
  65. static int FourSamples[16] = {
  66.     0,   8,  2, 10,
  67.     12,  4, 14,  6,
  68.     3,  11,  1,  9,
  69.     15,  7, 13,  5
  70. };
  71. static int FiveSamples[25] = {
  72.     0 ,  8, 23, 17,  2,
  73.     19, 12,  4, 20, 15,
  74.     3 , 21, 16,  9,  6,
  75.     14, 10, 24,  1, 13,
  76.     22,  7, 18, 11,  5
  77. };
  78. static int SixSamples[36] =    {
  79.     6 , 32,  3, 34, 35,  1,
  80.     7 , 11, 27, 28,  8, 30,
  81.     24, 14, 16, 15, 23, 19,
  82.     13, 20, 22, 21, 17, 18,
  83.     25, 29, 10,  9, 26, 12,
  84.     36,  5, 33,  4,  2, 31
  85. };
  86. static int SevenSamples[49] = {
  87.     22, 47, 16, 41, 10, 35,  4,
  88.     5 , 23, 48, 17, 42, 11, 29,
  89.     30,  6, 24, 49, 18, 36, 12,
  90.     13, 31,  7, 25, 43, 19, 37,
  91.     38, 14, 32,  1, 26, 44, 20,
  92.     21, 39,  8, 33,  2, 27, 45,
  93.     46, 15, 40,  9, 34,  3, 28
  94. };
  95. static int EightSamples[64] = {
  96.     8 , 58, 59,  5,  4, 62, 63,  1,
  97.     49, 15, 14, 52, 53, 11, 10, 56,
  98.     41, 23, 22, 44, 45, 19, 18, 48,
  99.     32, 34, 35, 29, 28, 38, 39, 25,
  100.     40, 26, 27, 37, 36, 30, 31, 33,
  101.     17, 47, 46, 20, 21, 43, 42, 24,
  102.     9 , 55, 54, 12, 13, 51, 50, 16,
  103.     64,  2,  3, 61, 60,  6,  7, 57
  104. };
  105.  
  106. void    AdaptiveRefineScanline(), FullySamplePixel(), FullySampleScanline(),
  107.         SingleSampleScanline();
  108. static int    ExcessiveContrast();
  109. static Scanline scan0, scan1, scan2;
  110.  
  111.  
  112. void SetRenderAbort()
  113. {
  114.     halt_rendering = 1 ;
  115. }
  116.  
  117. void
  118. raytrace(argc, argv)
  119. int argc;
  120. char **argv;
  121. {
  122.     int y, *tmpsamp;
  123.     Pixel *tmppix;
  124.     Float usertime, systime, lasttime;
  125.  
  126.     halt_rendering = 0 ;
  127.  
  128.     /*
  129.      * If this is the first frame,
  130.      * allocate scanlines, etc.
  131.      */
  132.     if (Options.framenum == Options.startframe)
  133.         RaytraceInit();
  134.     /*
  135.      * The top-level ray TopRay always has as its origin the
  136.      * eye position and as its medium NULL, indicating that it
  137.      * is passing through a medium with index of refraction
  138.      * equal to DefIndex.
  139.      */
  140.     TopRay.pos = Camera.pos;
  141.     TopRay.media = (Medium *)0;
  142.     TopRay.depth = 0;
  143.  
  144.     /*
  145.      * Always fully sample the bottom and top rows and the left
  146.      * and right column of pixels.  This minimizes artifacts that
  147.      * may arise when piecing together images.
  148.      */
  149.     printf("Sampling edges\n") ;
  150.     FullySampleScanline(0, &scan0);
  151.  
  152.     SingleSampleScanline(1, &scan1);
  153.     FullySamplePixel(0, 1, &scan1.pix[0], &scan1.samp[0]);
  154.     FullySamplePixel(Screen.xsize -1, 1, &scan1.pix[Screen.xsize -1],
  155.         &scan1.samp[Screen.xsize -1]);
  156.  
  157.     printf("Sampling Picture.....\n") ;
  158.     lasttime = 0;
  159.     for (y = 1; y < Screen.ysize; y++) {
  160.         HandleEvent() ;            /* Something to keep Mac people happy */
  161.         if(halt_rendering) return ;
  162.         SingleSampleScanline(y+1, &scan2);
  163.         FullySamplePixel(0, y+1, &scan2.pix[0], &scan2.samp[0]); /* Left Edge */
  164.         FullySamplePixel(Screen.xsize -1, y+1,                     /* Right Edge */
  165.             &scan2.pix[Screen.xsize -1],
  166.             &scan2.samp[Screen.xsize -1]);
  167.  
  168.         if (Sampling.sidesamples > 1)
  169.             AdaptiveRefineScanline(y,&scan0,&scan1,&scan2);
  170.  
  171.         PictureWriteLine(y,scan0.pix);
  172.  
  173.         /* scan0 = scan1 = scan2 = scan0 */
  174.         tmppix = scan0.pix;
  175.         tmpsamp = scan0.samp;
  176.         scan0.pix = scan1.pix;
  177.         scan0.samp = scan1.samp;
  178.         scan1.pix = scan2.pix;
  179.         scan1.samp = scan2.samp;
  180.         scan2.pix = tmppix;
  181.         scan2.samp = tmpsamp;
  182.  
  183.         if ((y-1) % Options.report_freq == 0) {
  184.             printf("Finished line %d (%lu rays",y-1,Stats.EyeRays);
  185.             if (Options.verbose) {
  186.                 /*
  187.                  * Report total CPU and split times.
  188.                  */
  189.                 RSGetCpuTime(&usertime, &systime);
  190.                 printf(", %2.2f sec,",usertime+systime);
  191.                 printf(" %2.2f split", usertime+systime-lasttime);
  192.                 lasttime = usertime+systime;
  193.             }
  194.             printf(")\n");
  195.         }
  196.  
  197.     }
  198.     /*
  199.      * Supersample last scanline.
  200.      */
  201.     for (y = 1; y < Screen.xsize -1; y++) {
  202.         if (scan0.samp[y] != SUPERSAMPLED)
  203.             FullySamplePixel(y, Screen.ysize -1,
  204.                 &scan0.pix[y],
  205.                 &scan0.samp[y]);
  206.     }
  207.     PictureWriteLine(y,scan0.pix);
  208.     
  209.     /* Lets get rid of all that extra memory we needed */
  210.     Free(scan0.pix) ;
  211.     Free(scan1.pix) ;
  212.     Free(scan2.pix) ;
  213.     Free(scan0.samp) ;
  214.     Free(scan1.samp) ;
  215.     Free(scan2.samp) ;
  216. }
  217.  
  218. void
  219. SingleSampleScanline(line, data)
  220. int line;
  221. Scanline *data;
  222. {
  223.     Float upos, vpos, yp;
  224.     int x, usamp, vsamp;
  225.     Pixel tmp;
  226.  
  227.     yp = line + Screen.miny - 0.5*Sampling.filterwidth;
  228.     for (x = 0; x < Screen.xsize; x++) {
  229.         HandleEvent() ;            /* Something to keep Mac people happy */
  230.         /*
  231.          * Pick a sample number...
  232.          */
  233.         data->samp[x] = nrand() * Sampling.totsamples;
  234.         /*
  235.          * Take sample corresponding to sample #.
  236.          */
  237.         usamp = data->samp[x] % Sampling.sidesamples;
  238.         vsamp = data->samp[x] / Sampling.sidesamples;
  239.  
  240.         vpos = yp + vsamp * Sampling.filterdelta;
  241.         upos = x + Screen.minx - 0.5*Sampling.filterwidth +
  242.                 usamp*Sampling.filterdelta;
  243.         if (Options.jitter) {
  244.             vpos += nrand()*Sampling.filterdelta;
  245.             upos += nrand()*Sampling.filterdelta;
  246.         }
  247.         TopRay.time = SampleTime(SampleNumbers[data->samp[x]]);
  248.         SampleScreen(upos, vpos, &TopRay,
  249.             &data->pix[x], SampleNumbers[data->samp[x]]);
  250.         if (Options.samplemap)
  251.             data->pix[x].alpha = 0;
  252.     }
  253. }
  254.  
  255. void
  256. FullySampleScanline(line, data)
  257. int line;
  258. Scanline *data;
  259. {
  260.     int x;
  261.  
  262.     for (x = 0; x < Screen.xsize; x++) {
  263.         HandleEvent() ;            /* Something to keep Mac people happy */
  264.         data->samp[x] = UNSAMPLED;
  265.         FullySamplePixel(x, line, &data->pix[x], &data->samp[x]);
  266.     }
  267. }
  268.  
  269. void
  270. FullySamplePixel(xp, yp, pix, prevsamp)
  271. int xp, yp;
  272. Pixel *pix;
  273. int *prevsamp;
  274. {
  275.     Float upos, vpos, u, v;
  276.     int x, y, sampnum;
  277.     Pixel ctmp;
  278.  
  279.     if (*prevsamp == SUPERSAMPLED)
  280.         return;    /* already done */
  281.  
  282.     Stats.SuperSampled++;
  283.     if (*prevsamp == UNSAMPLED) {
  284.         /*
  285.          * No previous sample; initialize to black.
  286.          */
  287.         pix->r = pix->g = pix->b = pix->alpha = 0.;
  288.     } else {
  289.         if (Sampling.sidesamples == 1) {
  290.             *prevsamp = SUPERSAMPLED;
  291.             return;
  292.         }
  293.         x = *prevsamp % Sampling.sidesamples;
  294.         y = *prevsamp / Sampling.sidesamples;
  295.         pix->r *= Sampling.filter[x][y];
  296.         pix->g *= Sampling.filter[x][y];
  297.         pix->b *= Sampling.filter[x][y];
  298.         pix->alpha *= Sampling.filter[x][y];
  299.     }
  300.  
  301.     sampnum = 0;
  302.     xp += Screen.minx;
  303.     vpos = Screen.miny + yp - 0.5*Sampling.filterwidth;
  304.     for (y = 0; y < Sampling.sidesamples; y++,
  305.          vpos += Sampling.filterdelta) {
  306.         upos = xp - 0.5*Sampling.filterwidth;
  307.         for (x = 0; x < Sampling.sidesamples; x++,
  308.              upos += Sampling.filterdelta) {
  309.             if (sampnum != *prevsamp) {
  310.                 if (Options.jitter) {
  311.                     u = upos + nrand()*Sampling.filterdelta;
  312.                     v = vpos + nrand()*Sampling.filterdelta;
  313.                 } else {
  314.                     u = upos;
  315.                     v = vpos;
  316.                 }
  317.                 TopRay.time = SampleTime(SampleNumbers[sampnum]);
  318.                 SampleScreen(u, v, &TopRay, &ctmp,
  319.                     SampleNumbers[sampnum]);
  320.                 pix->r += ctmp.r*Sampling.filter[x][y];
  321.                 pix->g += ctmp.g*Sampling.filter[x][y];
  322.                 pix->b += ctmp.b*Sampling.filter[x][y];
  323.                 pix->alpha += ctmp.alpha*Sampling.filter[x][y];
  324.             }
  325.             if (++sampnum == Sampling.totsamples)
  326.                 sampnum = 0;
  327.         }
  328.     }
  329.  
  330.     if (Options.samplemap)
  331.         pix->alpha = 255;
  332.  
  333.     *prevsamp = SUPERSAMPLED;
  334. }
  335.  
  336. void
  337. AdaptiveRefineScanline(y, scan0, scan1, scan2)
  338. int y;
  339. Scanline *scan0, *scan1, *scan2;
  340. {
  341.     int x, done;
  342.  
  343.     /*
  344.      * Walk down scan1, looking at 4-neighbors for excessive contrast.
  345.      * If found, supersample *all* neighbors not already supersampled.
  346.      * The process is repeated until either there are no
  347.      * high-contrast regions or all such regions are already supersampled.
  348.      */
  349.  
  350.     do {
  351.         done = TRUE;
  352.         for (x = 1; x < Screen.xsize -1; x++) {
  353.             HandleEvent() ;            /* Something to keep Mac people happy */
  354.             /*
  355.               * Find min and max RGB for area we care about
  356.              */
  357.             if (ExcessiveContrast(x, scan0->pix, scan1->pix,
  358.                 scan2->pix)) {
  359.                 if (scan1->samp[x-1] != SUPERSAMPLED) {
  360.                     done = FALSE;
  361.                     FullySamplePixel(x-1, y,
  362.                         &scan1->pix[x-1],
  363.                         &scan1->samp[x-1]);
  364.                 }
  365.                 if (scan0->samp[x] != SUPERSAMPLED) {
  366.                     done = FALSE;
  367.                     FullySamplePixel(x, y-1,
  368.                         &scan0->pix[x],
  369.                         &scan0->samp[x]);
  370.                 }
  371.                 if (scan1->samp[x+1] != SUPERSAMPLED) {
  372.                     done = FALSE;
  373.                     FullySamplePixel(x+1, y,
  374.                         &scan1->pix[x+1],
  375.                         &scan1->samp[x+1]);
  376.                 }
  377.                 if (scan2->samp[x] != SUPERSAMPLED) {
  378.                     done = FALSE;
  379.                     FullySamplePixel(x, y+1,
  380.                         &scan2->pix[x],
  381.                         &scan2->samp[x]);
  382.                 }
  383.                 if (scan1->samp[x] != SUPERSAMPLED) {
  384.                     done = FALSE;
  385.                     FullySamplePixel(x, y,
  386.                         &scan1->pix[x],
  387.                         &scan1->samp[x]);
  388.                 }
  389.             }
  390.         }
  391.     } while (!done);
  392. }
  393.  
  394. static int
  395. ExcessiveContrast(x, pix0, pix1, pix2)
  396. int x;
  397. Pixel *pix0, *pix1, *pix2;
  398. {
  399.     Float mini, maxi, sum, diff;
  400.  
  401.     maxi = max(pix0[x].r, pix1[x-1].r);
  402.     if (pix1[x].r > maxi) maxi = pix1[x].r;
  403.     if (pix1[x+1].r > maxi) maxi = pix1[x+1].r;
  404.     if (pix2[x].r > maxi) maxi = pix2[x].r;
  405.  
  406.     mini = min(pix0[x].r, pix1[x-1].r);
  407.     if (pix1[x].r < mini) mini = pix1[x].r;
  408.     if (pix1[x+1].r < mini) mini = pix1[x+1].r;
  409.     if (pix2[x].r < mini) mini = pix2[x].r;
  410.  
  411.     diff = maxi - mini;
  412.     sum = maxi + mini;
  413.     if (sum > EPSILON && diff/sum > Options.contrast.r)
  414.         return TRUE;
  415.  
  416.     maxi = max(pix0[x].g, pix1[x-1].g);
  417.     if (pix1[x].g > maxi) maxi = pix1[x].g;
  418.     if (pix1[x+1].g > maxi) maxi = pix1[x+1].g;
  419.     if (pix2[x].g > maxi) maxi = pix2[x].g;
  420.  
  421.     mini = min(pix0[x].g, pix1[x-1].g);
  422.     if (pix1[x].g < mini) mini = pix1[x].g;
  423.     if (pix1[x+1].g < mini) mini = pix1[x+1].g;
  424.     if (pix2[x].g < mini) mini = pix2[x].g;
  425.  
  426.     diff = maxi - mini;
  427.     sum = maxi + mini;
  428.  
  429.     if (sum > EPSILON && diff/sum > Options.contrast.g)
  430.         return TRUE;
  431.  
  432.     maxi = max(pix0[x].b, pix1[x-1].b);
  433.     if (pix1[x].b > maxi) maxi = pix1[x].b;
  434.     if (pix1[x+1].b > maxi) maxi = pix1[x+1].b;
  435.     if (pix2[x].b > maxi) maxi = pix2[x].b;
  436.  
  437.     mini = min(pix0[x].b, pix1[x-1].b);
  438.     if (pix1[x].b < mini) mini = pix1[x].b;
  439.     if (pix1[x+1].b < mini) mini = pix1[x+1].b;
  440.     if (pix2[x].b < mini) mini = pix2[x].b;
  441.  
  442.     diff = maxi - mini;
  443.     sum = maxi + mini;
  444.     if (sum > EPSILON && diff/sum > Options.contrast.b)
  445.         return TRUE;
  446.  
  447.     return FALSE;
  448. }
  449.  
  450. Float
  451. SampleTime(sampnum)
  452. int sampnum;
  453. {
  454.     Float window, jitter = 0.0, res;
  455.  
  456.     if (Options.shutterspeed <= 0.)
  457.         return Options.framestart;
  458.     if (Options.jitter)
  459.         jitter = nrand();
  460.     window = Options.shutterspeed / Sampling.totsamples;
  461.     res = Options.framestart + window * (sampnum + jitter);
  462.     TimeSet(res);
  463.     return res;
  464. }
  465.  
  466. static void
  467. RaytraceInit()
  468. {
  469.  
  470.     switch (Sampling.sidesamples) {
  471.         case 1:
  472.             SampleNumbers = OneSample;
  473.             break;
  474.         case 2:
  475.             SampleNumbers = TwoSamples;
  476.             break;
  477.         case 3:
  478.             SampleNumbers = ThreeSamples;
  479.             break;
  480.         case 4:
  481.             SampleNumbers = FourSamples;
  482.             break;
  483.         case 5:
  484.             SampleNumbers = FiveSamples;
  485.             break;
  486.         case 6:
  487.             SampleNumbers = SixSamples;
  488.             break;
  489.         case 7:
  490.             SampleNumbers = SevenSamples;
  491.             break;
  492.         case 8:
  493.             SampleNumbers = EightSamples;
  494.             break;
  495.         default:
  496.             RLerror(RL_PANIC,
  497.                 "Sorry, %d rays/pixel not supported.\n",
  498.                     (char *)Sampling.totsamples,0,0);
  499.     }
  500.  
  501.     /*
  502.       * Allocate pixel arrays and arrays to store sampling info.
  503.       */
  504.     scan0.pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
  505.     scan1.pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
  506.     scan2.pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
  507.  
  508.     scan0.samp = (int *)Malloc(Screen.xsize * sizeof(int));
  509.     scan1.samp = (int *)Malloc(Screen.xsize * sizeof(int));
  510.     scan2.samp = (int *)Malloc(Screen.xsize * sizeof(int));
  511. }
  512.